package com.hancher.common.net;

import com.hancher.common.androidutil.LogUtil;
import com.hancher.common.javautil.EmptyUtil;
import com.hancher.common.net.cookie.CookieJarImpl;
import com.hancher.common.net.https.HttpsAdapter;
import com.hancher.common.net.interceptor.JumpInterceptor;
import com.hancher.common.net.interceptor.ProgressInterceptor;
import com.hancher.common.net.interceptor.ProgressListener;

import java.io.File;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * 作者 : Hancher ytu_shaoweijie@163.com <br/>
 * 时间 : 2021/2/4 15:17 <br/>
 * 描述 : 网络工具类
 */
public class NetUtil<S> {
    private static final long DEFAULT_TIMEOUT = 20L;
    Class<S> clazz;
    long timeOut = DEFAULT_TIMEOUT;
    String baseUrl = "";
    ProgressListener listener = null;
    boolean printLog = true;
    boolean useCookie = false;
    boolean useJson = true;
    boolean useJump = false;

    InputStream certification = null;
    InputStream bksFile = null;
    String password = null;

    public NetUtil(Class<S> clazz) {
        this.clazz = clazz;
    }
    //https://www.jianshu.com/p/a229722b55fe 上传
//    https://blog.csdn.net/qq_30574785/article/details/79024656 下载
//    https://blog.csdn.net/shiming_shi/article/details/91377521 监听

    public S build() {

        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        clientBuilder.connectTimeout(timeOut, TimeUnit.SECONDS);
        if (useCookie) {
            clientBuilder.setCookieJar$okhttp(CookieJarImpl.getInstance());
        }
        if (printLog) {
//            clientBuilder.addInterceptor(new LogInterceptor());
            // 不要用lamba，会导致log显示不好看
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
                @Override
                public void log(String message) {
                    String str;
                    if (message.length() > 3000 && !message.trim().startsWith("{")) {
                        str = "全埋点(网络):  大块数据：" + message.length();
                    } else {
                        str = "全埋点(网络):  " + message;
                    }
                    if (EmptyUtil.isNotEmpty(str) && (str.contains("--> GET") || str.contains("--> POST"))) {
                        LogUtil.d(str);
                    } else {
                        LogUtil.v(str);
                    }
                }
            });
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            clientBuilder.addInterceptor(logging);
        }
        if (listener != null) {
            clientBuilder.addInterceptor(new ProgressInterceptor(listener));
        }
        if (certification != null) {
            HttpsAdapter.SSLParams params = HttpsAdapter.getSslSocketFactory(new InputStream[]{certification}, bksFile, password);
            clientBuilder.sslSocketFactory(params.sSLSocketFactory, params.trustManager);
        }
        if (useJump) {
            clientBuilder.addInterceptor(new JumpInterceptor());
        }
        clientBuilder.setFollowRedirects$okhttp(false);
        OkHttpClient client = clientBuilder.build();
//        client.followRedirects();
//        client.followSslRedirects();

        Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .client(client);
        if (useJson) {
            retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
        }
//        else {
////            retrofitBuilder.addConverterFactory(SimpleXmlConverterFactory.create());
////            https://www.w3cschool.cn/jaxb2/jaxb2-8pa22zoi.html
//            retrofitBuilder.addConverterFactory(JaxbConverterFactory.create());
//        }
        Retrofit retrofit = retrofitBuilder.build();
        return retrofit.create(this.clazz);
    }

    public boolean isUseJump() {
        return useJump;
    }

    public NetUtil<S> setUseJump(boolean useJump) {
        this.useJump = useJump;
        return this;
    }

    public boolean isUseJson() {
        return useJson;
    }

    public NetUtil<S> setUseJson(boolean useJson) {
        this.useJson = useJson;
        return this;
    }

    public boolean isUseCookie() {
        return useCookie;
    }

    public NetUtil<S> setUseCookie(boolean useCookie) {
        this.useCookie = useCookie;
        return this;
    }

    public boolean isPrintLog() {
        return printLog;
    }

    public NetUtil<S> setPrintLog(boolean printLog) {
        this.printLog = printLog;
        return this;
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public NetUtil<S> setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
        return this;
    }

    public ProgressListener getListener() {
        return listener;
    }

    public NetUtil<S> setListener(ProgressListener listener) {
        this.listener = listener;
        return this;
    }

    public InputStream getCertification() {
        return certification;
    }

    public NetUtil<S> setCertification(InputStream certification) {
        this.certification = certification;
        return this;
    }

    public InputStream getBksFile() {
        return bksFile;
    }

    public NetUtil<S> setBksFile(InputStream bksFile) {
        this.bksFile = bksFile;
        return this;
    }

    public String getPassword() {
        return password;
    }

    public NetUtil<S> setPassword(String password) {
        this.password = password;
        return this;
    }

    public Class<S> getClazz() {
        return clazz;
    }

    public NetUtil<S> setClazz(Class<S> clazz) {
        this.clazz = clazz;
        return this;
    }

    public long getTimeOut() {
        return timeOut;
    }

    public NetUtil<S> setTimeOut(long timeOut) {
        this.timeOut = timeOut;
        return this;
    }

    public static RequestBody fileParam2Body(String value) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), value);
        return requestBody;
    }

    public static MultipartBody.Part fileParam2File(String key, File file) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
        MultipartBody.Part part = MultipartBody.Part.createFormData(key, file.getName(), requestBody);
        return part;
    }
}
